﻿using System;
using System.Data;
using NetDon.OA.Data.HelperClasses;
using NetDon.Utilities;
using SD.LLBLGen.Pro.ORMSupportClasses;


namespace NetDon.OA.Business
{
    public abstract class CachableServiceBase<T> : CacheManagerBase
        where T:class 
    {
        private readonly string _cacheKey;

        protected string CacheKey
        {
            get
            {
                return _cacheKey;
            }
        }

        protected CachableServiceBase(string cacheKey)
        {
            _cacheKey = cacheKey;
        }

        protected virtual string GenerateCacheKey(object key)
        {
            return _cacheKey + "_" + key;
        }

        protected abstract T OnLoadData(object key, ITransaction transaction);

        protected abstract object GetDataKey(T data);

        protected virtual bool OnRemoveData(object key, T data, ITransaction transaction)
        {
            return true;
        }

        protected virtual void OnRemoveDataComplete(object key, T data)
        {
            
        }

        protected virtual bool OnAddData(T data, ITransaction transaction)
        {
            return true;
        }

        protected virtual void OnAddDataComplete(object key, T data)
        {
            
        }

        protected virtual bool OnModifyData(object key, T data, ITransaction transaction)
        {
            return true;
        }

        protected virtual void OnModifyDataComplete(object key, T data)
        {
            
        }

        protected T GetData(object key)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            return GetData(key, null);
        }

        protected virtual T GetData(object key, ITransaction transaction)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            return GetCache(GenerateCacheKey(key), () => OnLoadData(key, transaction));
        }

        protected bool RemoveData(object key)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            var transaction = new Transaction(IsolationLevel.ReadCommitted, Guid.NewGuid().ToString());
            try
            {
                if(RemoveData(key, transaction))
                {
                    transaction.Commit();
                    return true;
                }
                else
                {
                    transaction.Rollback();
                    return false;
                }
            }
            catch (Exception)
            {
                transaction.Rollback();
                throw;
            }
        }

        protected virtual bool RemoveData(object key, ITransaction transaction)
        {
            var data = GetData(key);
            if (data == null)
            {
                return false;
            }
            if (OnRemoveData(key, data, transaction))
            {
                RemoveCache(GenerateCacheKey(key));
                OnRemoveDataComplete(key, data);
                return true;
            }
            return false;
        }

        protected bool AddData(T data)
        {
            if (data==null)
            {
                throw new ArgumentNullException("data");
            }
            var transaction = new Transaction(IsolationLevel.ReadCommitted, Guid.NewGuid().ToString());
            try
            {
                if(AddData(data, transaction))
                {
                    transaction.Commit();
                    return true;
                }
                else
                {
                    transaction.Rollback();
                    return false;
                }
            }
            catch (Exception)
            {
                transaction.Rollback();
                throw;
            }
        }

        protected virtual bool AddData(T data, ITransaction transaction)
        {
            if (OnAddData(data, transaction))
            {
                object key = GetDataKey(data);
                SetCache(GenerateCacheKey(key), data);
                OnAddDataComplete(key, data);
                return true;
            }
            return false;
        }

        protected bool ModifyData(object key, T data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            var transaction = new Transaction(IsolationLevel.ReadCommitted, Guid.NewGuid().ToString());
            try
            {
                if(ModifyData(key, data, transaction))
                {
                    transaction.Commit();
                    return true;
                }
                else
                {
                    transaction.Rollback();
                    return false;
                }
            }
            catch (Exception)
            {
                transaction.Rollback();
                throw;
            }
        }

        protected virtual bool ModifyData(object key, T data, ITransaction transaction)
        {
            if (OnModifyData(key, data, transaction))
            {
                SetCache(GenerateCacheKey(key), data);
                OnModifyDataComplete(key, data);
                return true;
            }
            return false;
        }
    }
}
